package MineGod;

import java.io.IOException;
import java.util.ArrayList;

import org.lwjgl.opengl.GL11;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Image;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;


public class Player {
	private Animation anim;
	private static Image[] ss;
	
	public double xPos = Chunk.CHUNK_PIXEL_WIDTH/2;
	public double yPos = Chunk.CHUNK_PIXEL_HEIGHT/2;
	public boolean leftFacing = false;
	private double width;
	private double height;
	private double maskWidth;
	private double maskHeight;
	
	public int[] inventory = new int[5]; //[gunpowder, diamond, something else, ..., something else]
	
	
	public ProjectileType[] weapons = {ProjectileType.small, ProjectileType.big, ProjectileType.destroy};
	public int weaponSelectedIndex = 0;
	
	public double zIndex = -1;
	public double xSpeed = 0;
	public double ySpeed = 0;
	private double maxYSpeed = 0.15;
	
	public double maxHP = 100;
	public double hp = 100;
	private int invincible = 0; //Time left that player is invincible.
	private int fireInvincible = 0; //Time left that player is fire invincible.
	private int onFire = 0;
	private EmitterFire fireEffect = new EmitterFire();
	
	private final double startX = xPos;
	
		
	private double maxXSpeed = 0.15;
	private int[] walking = {0, 0}; // walking[0] is the left speed? walking[1] is the right speed?
	private int[] climbing = {0, 0}; // walking[0] is the left speed? walking[1] is the right speed?
	
	private Rectangle mask;
	
	//public Texture texture;
	
	public Player(){
		if(MineGod.godMode){
			inventory[0] = 100;
			inventory[1] = 100;
		} else {
			inventory[0] = 0;
			inventory[1] = 0;
		}
		if (ss == null){
			ss = new Image[4];
			try {
				for (int i = 0; i<4; i++){
					ss[i] = new Image(TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("res/player"+i+".png")));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		anim = new Animation(false);
		for (int i = 0; i<ss.length; i++){
			anim.addFrame(ss[i], 90);
		}
		anim.setLooping(true);
		anim.start();
		width = 16;
		height = 16;
		maskWidth = 16;
		maskHeight = 16;
		mask = new Rectangle((float)(xPos+(width-maskWidth)/2), (float)(yPos+(height-maskHeight)/2), (float)(maskWidth), (float)maskHeight);
	}

	public void damage(double dmg, DamageType src){
		if (!(MineGod.godMode)){
			if (src != DamageType.onFire && invincible == 0){
				hp -= dmg;		// This would be less if you didn't die instantly
				invincible = 500; // this would greater if you didn't die instantly
				if (src == DamageType.lava){
					if (onFire==0){
						//fireEffect = new EmitterFire();
						fireEffect.off = false;
						//MineGod.emitters.add(fireEffect);
					}
					onFire = 5000;
				}
			}else if (src == DamageType.onFire && fireInvincible == 0){
				hp-=dmg;
				fireInvincible = 270;
			}
			GUILabelHealthBar.refreshHealthBar();
		}
	}
	
	public void doLogic(int delta, Chunk prevChunk, Chunk currChunk, Chunk nextChunk){
		anim.update((long)delta);
		if (!(Utils.pointToBlock(xPos+width/2, yPos+height/2).isSolid)){
			updateMovement(delta);
		}
		updatePhysics(delta, prevChunk, currChunk, nextChunk);
		updateInvincibility(delta);
		updateOnFire(delta);
		checkCurrBlockSolidity();
		checkInLava();
		//calcFacing();
		mask.setLocation((float)(xPos + (maskWidth-width)/2), (float)(yPos+(maskHeight-height)/2));
		//jumpLogic(delta);
		//updateLasers(delta);
		fireEffect.step(delta);
	}
	
	public void updateInvincibility(int delta){
		if (invincible > 0){
			invincible -= delta;
			if (invincible < 0){
				invincible = 0;
			}
			//System.out.println("invincibiliy: " + invincible);
		}
		if (fireInvincible > 0){
			fireInvincible -= delta;
			if (fireInvincible < 0){
				fireInvincible = 0;
			}
			//System.out.println("invincibiliy: " + invincible);
		}
	}
	
	public void updateOnFire(int delta){
		if (onFire > 0){
			onFire -= delta;
			this.damage(1, DamageType.onFire);
			if (Utils.pointToBlock(xPos+width/2, yPos+height/2).type == BlockType.water){
				fireEffect.off = true;
				//fireEffect = null;
				onFire = 0;
			}
			if (onFire < 0){
				fireEffect.off = true;
				//fireEffect = null;
				onFire = 0;
			}
			//System.out.println("invincibiliy: " + invincible);
		} else {
			fireEffect.off = true;
		}
	}
	
	public void setOnFireZero(){
		fireEffect.off = true;
		//fireEffect = null;
		onFire = 0;
	}
	
	public void checkCurrBlockSolidity(){
		if (Utils.pointToBlock(xPos+width/2, yPos+height/2).isSolid){
			this.damage(5, DamageType.suffocate);
		}
	}
	
	public void checkInLava(){
		if (Utils.pointToBlock(xPos+width/2, yPos+height/2).type == BlockType.lava){
			this.damage(15, DamageType.lava);
		}
	}
	
	public void updateMovement(int delta){
		xSpeed = maxXSpeed*walking[0] + maxXSpeed*walking[1];
		ySpeed = maxYSpeed*climbing[0] + maxYSpeed*climbing[1];
		if (xSpeed != 0 && ySpeed != 0){
			xSpeed = xSpeed/1.41;
			ySpeed = ySpeed/1.41;
		}
	}
	
	public void updatePhysics(int delta, Chunk prevChunk, Chunk currChunk, Chunk nextChunk){
		climbingPhysics(delta, prevChunk, currChunk, nextChunk);
		horizontalPhysics(delta, prevChunk, currChunk, nextChunk);
		
		if (ySpeed > maxYSpeed){
			ySpeed = maxYSpeed;
		}
		
		double slowdown = 1;
		
		if (Utils.pointToBlock(xPos+width/2, yPos+height/2).isLiquid){
			slowdown = .6;
		}
		xPos += xSpeed*delta*slowdown;
		yPos += ySpeed*delta*slowdown;

		if(xPos < 0){
			xPos = 0;
		}
		if(xPos > startX){
			MineGod.worldPosition = xPos - startX;
		} else {
			MineGod.worldPosition = 0;
		}
		/*
		if (x > Raid.windowWidth){
			x = Raid.windowWidth;
		} else if (x < 0){
			x = 0;
		}
		*/
		if (yPos+height > MineGod.gameHeight){
			yPos = MineGod.gameHeight-height;
		} else if (yPos < 0){
			yPos = 0;
		}
	}

	
	public void horizontalPhysics(int delta, Chunk prevChunk, Chunk currChunk, Chunk nextChunk){
		Rectangle newMask = getNextMask((float)xSpeed*delta, 0f);
		CollisionGroup sideBlocks = getSideBlocks(prevChunk, currChunk, nextChunk, newMask);
		if (xSpeed > 0){
			for (BlockMask blockMask: new BlockMask[] {sideBlocks.topRight, sideBlocks.bottomRight}){
				if (blockMask.block != null && blockMask.block.isSolid && Utils.intersects(blockMask.mask, newMask)){
					xSpeed = 0;
					xPos = blockMask.xPos - width + (width-maskWidth)/2;
					break;
				}
			}
		} else if (xSpeed < 0) {
			for (BlockMask blockMask: new BlockMask[] {sideBlocks.topLeft, sideBlocks.bottomLeft}){
				if (blockMask.block != null && blockMask.block.isSolid && Utils.intersects(blockMask.mask, newMask)){
					xSpeed = 0;
					xPos = blockMask.xPos + Block.WIDTH - (width-maskWidth)/2;
					break;
				}
			}
		}
	}
	
	public void climbingPhysics(int delta, Chunk prevChunk, Chunk currChunk, Chunk nextChunk){
		Rectangle newMask = getNextMask(0f, (float)ySpeed*delta);
		CollisionGroup sideBlocks = getSideBlocks(prevChunk, currChunk, nextChunk, newMask);
		if (ySpeed > 0){
			for (BlockMask blockMask: new BlockMask[] {sideBlocks.bottomLeft, sideBlocks.bottomRight}){
				if (blockMask.block != null && blockMask.block.isSolid && Utils.intersects(blockMask.mask, newMask)){
					ySpeed = 0;
					yPos = blockMask.yPos - height + (height-maskHeight)/2;
					break;
				}
			}
		} else if (ySpeed < 0) {
			for (BlockMask blockMask: new BlockMask[] {sideBlocks.topLeft, sideBlocks.topRight}){
				if (blockMask.block != null && blockMask.block.isSolid && Utils.intersects(blockMask.mask, newMask)){
					ySpeed = 0;
					yPos = blockMask.yPos + Block.WIDTH - (height-maskHeight)/2;
					break;
				}
			}
		}
	}
	
	
	
	
	
	
	public Rectangle getNextMask(float xs, float ys){
		return new Rectangle((float)(xPos+(width-maskWidth)/2) + xs, (float)(yPos+(height-maskHeight)/2) + ys, (float)(maskWidth), (float)maskHeight);
	}
	
	public CollisionGroup getSideBlocks(Chunk prevChunk, Chunk currChunk, Chunk nextChunk, Rectangle nextMask){
		double relativeXPos = nextMask.getMinX() % Chunk.CHUNK_PIXEL_WIDTH;
		if (relativeXPos < Chunk.CHUNK_PIXEL_WIDTH - maskWidth){
			return currChunk.getCollidedSideBlocks(nextMask.getMinX(), nextMask.getMinY(), nextMask.getWidth(), nextMask.getHeight());
		} else {
			CollisionGroup group1 = currChunk.getCollidedLeftSideBlocks(nextMask.getMinX(), nextMask.getMinY(), nextMask.getWidth(), nextMask.getHeight());
			CollisionGroup group2 = nextChunk.getCollidedLeftSideBlocks(nextMask.getMinX()+Block.WIDTH, nextMask.getMinY(), nextMask.getWidth(), nextMask.getHeight());
			return new CollisionGroup(group1.topLeft, group2.topLeft, group1.bottomLeft, group2.bottomLeft);
		}
		
	}
	
	
	
	public void walkRight(int motion){
		walking[1] = motion;
	}
	
	public void walkLeft(int motion){
		walking[0] = motion;
	}
	
	public void climbUp(int motion){
		climbing[1] = motion;
	}
	
	public void climbDown(int motion){
		climbing[0] = motion;
	} 
	
	
	public double getScreenX(){
		if (xPos < startX){
			return xPos;
		} else {
			return startX;
		}
	}
	
	public ProjectileType getCurrentWeaponType(){
		return weapons[weaponSelectedIndex];
	}
	
	
	public int getNextUsableInventorySlot(){
		for(int i = 1; i < weapons.length; i++){
			if(hasAmpleResourcesForWeapon((weaponSelectedIndex+i)%weapons.length)){
				return (weaponSelectedIndex+i)%weapons.length;
			}
		}
		return weaponSelectedIndex;
	}
	
	public boolean hasAmpleResourcesForWeapon(int weaponIndex){
		switch(weaponIndex){
			case 0:  // ProjectileEntitySmall
				return true;
			case 1: // ProjectileEntityBig: Must have 5 gunpowder
				if(inventory[0] >= 1){
					return true;
				}
				break;
			case 2: // ProjectileEntityBig: Must have 1 diamond
				if(inventory[1] >= 1){
					return true;
				}
			default:
				return false;
		}
		return false;
	}
	
	
	
	public void render(){
		fireEffect.render();
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
		//texture.bind();
		anim.getCurrentFrame().bind();
		double renderX = getScreenX();
		if (onFire > 0) {
			GL11.glColor3d(1.0, 0, 0);
		} else {
			GL11.glColor3d(1.0, 1.0, 1.0);
		}
		if (leftFacing) {
		GL11.glBegin(GL11.GL_QUADS);
			GL11.glNormal3d(0, 0, 1);
			GL11.glTexCoord2d(0.0, 0.0);
			GL11.glVertex3d((renderX+width), yPos, zIndex);
			GL11.glTexCoord2d(1.0, 0.0);
			GL11.glVertex3d(renderX, yPos, zIndex);
			GL11.glTexCoord2d(1.0, 1.0);
			GL11.glVertex3d(renderX, (yPos+height), zIndex);
			GL11.glTexCoord2d(0.0, 1.0);
			GL11.glVertex3d((renderX+width), (yPos+height), zIndex);
		GL11.glEnd();
		} else{
		GL11.glBegin(GL11.GL_QUADS);
			GL11.glNormal3d(0, 0, 1);
			GL11.glTexCoord2d(0.0, 0.0);
			GL11.glVertex3d(renderX, yPos, zIndex);
			GL11.glTexCoord2d(1.0, 0.0);
			GL11.glVertex3d((renderX+width), yPos, zIndex);
			GL11.glTexCoord2d(1.0, 1.0);
			GL11.glVertex3d((renderX+width), (yPos+height), zIndex);
			GL11.glTexCoord2d(0.0, 1.0);
			GL11.glVertex3d(renderX, (yPos+height), zIndex);
		GL11.glEnd();
		
		
		}
		
	}
}
